BREAKING: stop publishing to Docker Hub (GHCR only) + migrate build to shared bake reusable - #45
Merged
Merged
Conversation
BREAKING CHANGE: images are no longer published to Docker Hub.
docker.io/netresearch/docker-mariadb stops receiving updates. The existing
tags stay pullable but frozen; all future builds go to
ghcr.io/netresearch/docker-mariadb only. The reusable build workflow logs
into exactly one registry, and the owner decided to consolidate on GHCR.
Migration of the build itself:
- docker-publish.yml now has zero step-level `uses:`; the single job calls
netresearch/.github/.github/workflows/build-container-bake.yml@main.
- New docker-bake.hcl drives the build. Tags/labels are not hardcoded: an
empty `docker-metadata-action` target is inherited by the `app` target and
populated at build time by the tag/label bake files docker/metadata-action
generates.
- `bake-source: "."` is required because those generated files live in
$RUNNER_TEMP on the runner, which the default git-remote bake context
cannot read.
- `flavor: latest=true` is re-expressed as `type=raw,value=latest`. Verified
against docker/metadata-action v6.2.0 run locally for push, schedule and
pull_request: the GHCR tag set and the version output (and therefore the
org.opencontainers.image.version label) are identical to today.
- `cache: ${{ github.event_name != 'schedule' }}` — the nightly run exists to
pick up a fresh `FROM mariadb` base image and the apt upgrade layer; with
the GHA layer cache it would restore the old chain and rebuild nothing.
- `scan: false` keeps parity: this workflow never scanned, and container
scanning already runs in ci.yml via docker-image-ci.
- Signing stays cosign keyless (OIDC); it now signs each pushed tag instead
of the single pushed digest.
- The calling job must grant `security-events: write` because a called
workflow's job permissions are validated statically at startup.
The DOCKER_USERNAME / DOCKER_PASSWORD secrets are now unused.
Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
Dependency ReviewThe following issues were found:
License Issues.github/workflows/docker-publish.yml
OpenSSF Scorecard
Scanned Files
|
CybotTM
added a commit
to netresearch/.github
that referenced
this pull request
Jul 22, 2026
Exposes `docker/metadata-action`'s `flavor:` as an input. ## Why Supplying an explicit `metadata-tags` list leaves `flavor` at its default `latest=auto`, which appends `latest` on a tag push. A caller whose tag list already carries an explicit `type=raw,value=latest` — the way to reproduce a previous `flavor: latest=true` — therefore emits `latest` **twice** on tag pushes. Found while migrating [netresearch/docker-mariadb#45](netresearch/docker-mariadb#45), where it was measured by running the pinned action locally against a synthesised tag-push context. ## Backward compatibility Default `""`. An unset GitHub Actions input already reads as `""`, so `flavor: ""` is byte-for-byte what `metadata-action` received before this change — existing callers are unaffected. ## Validation - `actionlint` clean
Two review findings. metadata-flavor: an explicit metadata-tags list leaves metadata-action's flavor at `latest=auto`, which appends `latest` again on a tag push. The explicit `type=raw,value=latest` already reproduces the previous `flavor: latest=true` on every event, so `latest=false` turns the implicit one off and exactly one `latest` is emitted. Uses the metadata-flavor input added in netresearch/.github#267. cache: was `!= 'schedule'`, so a push build was cached. Since the nightly rebuilds without cache to pick up `apt upgrade`, a subsequent cached push would restore the pre-upgrade layer chain and overwrite `:latest` / `:master` with a LESS patched image than the nightly had just published. Cache is now limited to pull_request, so every run that publishes rebuilds for real. Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



docker.io/netresearch/docker-mariadbwill no longer receive updates.This repo currently pushes the same digest to both
ghcr.io/netresearch/docker-mariadband
docker.io/netresearch/docker-mariadb. The Docker Hub repository is public and has18,725 pulls (verified via the Docker Hub API today; its
last_updatedwas thismorning's nightly run). This PR drops the
docker.ioimage name and the seconddocker/login-action, so:docker pull netresearch/docker-mariadb(:latest,:master,:nightly)keeps getting the image published before this PR merges, frozen forever — no more
base-image refreshes, no more OS security patches.
ghcr.io/netresearch/docker-mariadbonly.nothing errors, the image just silently stops ageing.
This is an explicit owner decision, not a side effect of the migration. It also happens to
be the only shape the shared reusable supports —
build-container-bake.ymllogs intoexactly one registry (
registry:input), so a dual-registry push is not reproduciblethrough it.
Recommended follow-up (deliberately NOT done in this PR)
netresearch/docker-mariadbon Docker Hub saying the image is unmaintained and pointingat
ghcr.io/netresearch/docker-mariadb. Nothing in this repo pushes the Hub description,so this is a manual step in the Docker Hub UI.
DOCKER_USERNAME/DOCKER_PASSWORDrepository secrets.What else changed: zero step-level actions
docker-publish.ymlhad 7 step-leveluses:(checkout, cosign-installer, setup-buildx,2× login-action, metadata-action, build-push-action). It now has none — one job calls
netresearch/.github/.github/workflows/build-container-bake.yml@main, and the build isdescribed by a new
docker-bake.hcl.Before / after
mastermaster,latestmaster,latestschedulenightly,master,latestnightly,master,latestpull_request(built, not pushed)pr-N,latestpr-N,latestorg.opencontainers.image.versionmaster/nightly/pr-N)COSIGN_EXPERIMENTAL=true,id-token: write,cosign sign --yes …@digest, no--key)sign: truebake --print(:master,:latest)linux/amd64; noplatforms:set)attest/sbomleft at reusable defaultfalseschedulescan: false)security-events: write16 14 * * *, push/PR onmasterIntentional deltas, spelled out
docker buildx bake --printand runscosign sign --yes <tag>for each. Cosign resolvesthe tag to its digest and stores the signature at the digest, so the end state is
equivalent — but it is a tag→digest resolution after the push rather than the digest
the build returned, and it signs the same digest twice (once via
:master, once via:latest). Harmless here, but it is not literally the old digest-pinned command.The reusable defaults
cache: true; this PR passescache: ${{ github.event_name != 'schedule' }}. Rationale: the nightly run exists to pulla fresh
FROM mariadb(unpinned floating tag) and re-run theapt-get upgradelayer —with
cache-fromit would restore the old layer chain and rebuild nothing, silentlyturning that security refresh into a no-op. Push/PR runs keep the cache for speed.
There is no
workflow_dispatchtrigger here, so nothing to special-case for it; if oneis added later it should be treated like
schedule.For strict parity instead, set
cache: false— push builds would then also alwaysre-resolve
FROM mariadb.security-events: writeadded to the calling job. A called workflow's jobpermissions are validated statically at workflow startup, before any
if:— the callermust grant the union of everything
build-container-bake.ymldeclares, or the run failswith
startup_failure. Granted even thoughscan: false.scan: false. This workflow never scanned, and container scanning already runs inci.yml(docker-image-ci.yml→build-container.yml,scan: true) on push and PR.Flip to
trueif you also want the nightly rebuild scanned — the permission is in place.DOCKER_META_IMAGES/DOCKER_META_VERSIONas build args; the Dockerfile does notdeclare them, so BuildKit emits an "unused build arg" warning. Cosmetic.
Explicitly not added
attest: trueon the bake reusable is buildxprovenance=mode=max(in-image BuildKit attestation) — a different mechanism fromactions/attest-build-provenance. This repo has neither today, so neither was added.If
gh attestation verify-able provenance is wanted, add a second job callingnetresearch/.github/.github/workflows/attest-image.yml@mainwith thebake-metadataoutput and
attestations: write.platforms, preserving that. Adding arm64 is a separate decision.becomes false. (Unrelated pre-existing observation, not touched: both microbadger badges
at the top are dead —
images.microbadger.comno longer resolves.)How this was verified
docker/metadata-actionv6.2.0 dist (
dc80280…, confirmed via the API to be the v6.2.0 tag object) locally undernode, with synthesised
push/schedule/pull_requestcontexts for this repo: oncewith the old config (2 images, default tags,
flavor: latest=true) and once with the newone (ghcr only, explicit
metadata-tags). The GHCR tag lists and theversionoutput(which drives
org.opencontainers.image.version) match exactly for all three events;only the
docker.io/...lines disappear.type=rawhas the lowest priority (200), solateststays a secondary tag exactly asflavor: latest=trueproduced it.docker-metadata-action-bake-tags.jsonand-bake-labels.jsonthat run wrote intodocker buildx bake -f docker-bake.hcl -f <tags> -f <labels> app --print, together withthe
--set *.cache-from/cache-tooverrides the reusable applies. Theapptargetresolves with the expected tags, labels and cache config.
jqover that--printoutput:SIGN_TAGS=:master+:latest,SCAN_REFS=:master.docker buildx bake -f docker-bake.hcl appcompletedlocally against the current Dockerfile (exit 0, image exported).
actionlint .github/workflows/docker-publish.yml→ clean, exit 0.build / Build Container (Bake)on this PR succeeded (nostartup_failure, so the permission union is right), built theapptarget, and theenumerate step resolved exactly
ghcr.io/netresearch/docker-mariadb:pr-45and:latest— matching the locally predictedpull_requesttag set. Nothing was pushed(
push: falseon PRs) and nodocker.io/...reference appears anywhere in the run.build-container-bake.yml,attest-image.yml, andci.yml(to confirm scanning is already covered).yamllintis broken in this environment (missing module), so YAML stylelint was not run —
lint-yamlinci.ymlcovers it. The live push + cosign path cannotbe exercised outside Actions; it is inherited unchanged from the reusable.
Review follow-up (owner decisions)
Base-image pulls become unauthenticated — accepted
Removing the
docker.iologin also removed authenticated Docker Hub pulls of theFROM mariadbbase image, not just the push. Anonymous pulls are subject to Docker Hub'sstricter anonymous rate limit, so a busy build day can intermittently fail with
toomanyrequests.The owner has accepted this trade-off rather than expanding the shared reusable with a
pull-registry credentials interface, or mirroring the base image into GHCR. If rate limiting
turns out to bite in practice, those two options remain open — the second is the durable fix.
Credential removal — check before deleting
An org-wide code search finds
DOCKER_PASSWORDreferenced by this repository only, so theDOCKER_USERNAME/DOCKER_PASSWORDorg secrets look unused after this merge. That searchcan miss dynamic references, so confirm before deleting them rather than treating this as
proof.
Two review findings fixed
latestwas emitted twice on a tag push — an explicitmetadata-tagslist leavesflavoratlatest=auto, which appendslateston top of the explicittype=raw,value=latestmetadata-flavor: latest=false, using the input added in netresearch/.github#267. Exactly onelatestnow.pushbuild could publish a less patched image than the nightly had just published: the nightly rebuilds uncached to pick upapt upgrade, but a following cached push restored the pre-upgrade layer chain and overwrote:latest/:mastercachelimited topull_request. Every run that publishes now rebuilds for real.Not verified here: neither the schedule nor the tag-push path can be exercised from a pull
request, so both changes are established by reading the reusable's
Compose bake --set overridesstep and metadata-action's flavor handling, not by execution.